07. Updating UI - Code
L6 A07 Updating UI - Code
In this step, you’ll implement updating the UI based on the authentication state. When the user is logged in, you can personalize their home screen by displaying their name. You will also update the Login button to be a Logout button when the user is logged in.
The first thing you need to do is provide a way for other classes in the app to know when a user has logged in or out. For this purpose, the
FirebaseUserLiveData.ktclass is already created for you. However, the class doesn’t do anything yet as the value of theLiveDataisn’t being updated.Since you are using the FirebaseAuth library, you can listen to changes to the logged in user with the
FirebaseUser.AuthStateListenercallback that’s implemented for you as part of the FirebaseUI library. This callback will get triggered whenever a user logs in or out of your app.Notice that
FirebaseUserLiveData.ktdefines theauthStateListenervariable. You will use this variable to store the value of theLiveData. TheauthStateListenervariable was created so that you can properly start and stop listening to changes in the auth state based on the state of your application. For example, if the user puts the app into the background, then the app should stop listening to auth state changes in order to prevent any potential memory leaks.Update
authStateListenerso that the value of yourFirebaseUserLiveDatacorresponds to the current Firebase user.
FirebaseUserLiveData.kt
private val authStateListener = FirebaseAuth.AuthStateListener { firebaseAuth ->
value = firebaseAuth.currentUser
}
- Next, in
LoginViewModel.kt, create anauthenticationStatevariable based off of theFirebaseUserLiveDataobject you just implemented. By creating thisauthenticationStatevariable, other classes can now query for whether the user is logged in or not through theLoginViewModel.
LoginViewModel.kt
val authenticationState = FirebaseUserLiveData().map { user ->
if (user != null) {
AuthenticationState.AUTHENTICATED
} else {
AuthenticationState.UNAUTHENTICATED
}
}
- Now in
MainFragment.kt’sobserveAuthenticationState()you can use theauthenticationStatevariable you just added inLoginViewModeland change the UI accordingly. If there is a logged-in user,authButtonshould display Logout.
MainFragment.kt
private fun observeAuthenticationState() {
val factToDisplay = viewModel.getFactToDisplay(requireContext())
viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
when (authenticationState) {
LoginViewModel.AuthenticationState.AUTHENTICATED -> {
binding.authButton.text = getString(R.string.logout_button_text)
binding.authButton.setOnClickListener {
// TODO implement logging out user in next step
}
// TODO 2. If the user is logged in,
// you can customize the welcome message they see by
// utilizing the getFactWithPersonalization() function provided
}
else -> {
// TODO 3. Lastly, if there is no logged-in user,
// auth_button should display Login and
// launch the sign in screen when clicked.
}
}
})
}
- If the user is logged in, you can customize the welcome message they see by utilizing the
getFactWithPersonalization()function provided inMainFragment.
MainFragment.kt
binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
- Lastly, if there is no logged-in user (when
authenticationStateis anything other thanLoginViewModel.AuthenticationState.AUTHENTICATED),auth_buttonshould display “Login” and launch the sign in screen when clicked. There should also be no personalization of the message displayed.
MainFragment.kt
binding.authButton.text = getString(R.string.login_button_text)
binding.authButton.setOnClickListener { launchSignInFlow() }
binding.welcomeText.text = factToDisplay
- With all the steps completed, your final
observeAuthenticationState()method should look similar to the example shown below.
MainFragment.kt
private fun observeAuthenticationState() {
val factToDisplay = viewModel.getFactToDisplay(requireContext())
viewModel.authenticationState.observe(viewLifecycleOwner, Observer { authenticationState ->
// TODO 1. Use the authenticationState variable you just added
// in LoginViewModel and change the UI accordingly.
when (authenticationState) {
// TODO 2. If the user is logged in,
// you can customize the welcome message they see by
// utilizing the getFactWithPersonalization() function provided
LoginViewModel.AuthenticationState.AUTHENTICATED -> {
binding.welcomeText.text = getFactWithPersonalization(factToDisplay)
binding.authButton.text = getString(R.string.logout_button_text)
binding.authButton.setOnClickListener {
// TODO implement logging out user in next step
}
}
else -> {
// TODO 3. Lastly, if there is no logged-in user,
// auth_button should display Login and
// launch the sign in screen when clicked.
binding.welcomeText.text = factToDisplay
binding.authButton.text = getString(R.string.login_button_text)
binding.authButton.setOnClickListener {
launchSignInFlow()
}
}
}
})
}
- Now the UI should update according to whether a user is logged in or not. Run the app again. If everything is working properly, the home screen should now greet you by your name in addition to displaying an Android fact. The Login button should also now display Logout.
- Since the app allows users to login, it should also provide them with a way to logout. Here’s an example of how to log out a user with just one line of code:
AuthUI.getInstance().signOut(requireContext())
In MainFragment.kt’s observeAuthenticationState(), add the logout logic so that the auth_button functions correctly when there is a logged in user.